package org.andes.kownledge.operator.executable;

import java.util.ArrayList;
import java.util.List;

import org.andes.base.Bindings;
import org.andes.base.Unification;
import org.andes.kownledge.operator.Executable;
import org.andes.kownledge.operator.Key;
import org.andes.kownledge.operator.NoAtom;
import org.andes.kownledge.operator.Predication;
import org.andes.kownledge.operator.Term;
import org.andes.kownledge.operator.func.Func;
import org.andes.sgg.st;

public class Not extends Executable{
	

	
	
	private List<NoAtom> funcs=new ArrayList<NoAtom>();
	public Not(){
		
	}
	public Not(NoAtom func1){
		funcs.add(func1);
	}
//	;;; The executable (not <proposition>) returns a set containing the
//	;;; given state if the given atomic proposition does not unify with
//	;;; any working memory element.  If the proposition does unify with
//	;;; some wme, it returns NIL.
//	;;;
//	;;; Not also includes an optional second argument that is a test
//	;;; proposition. If present this proposition will be evaluated with 
//	;;; the bindings substituted and iff it returns t the not will
//	;;; return nil.
//
//	(defun execute-not (Ex St)
//	  "Returns NIL if the <prop> of executable (not <prop> &optional <test>) 
//	   matches a wme and <test> if present returns t, a set consisting of 
//	   the given state otherwise."
//	  (if (= (length (cdr Ex)) 2)
//	      (execute-test-not Ex St)
//	    (execute-unary-not Ex St)))
	@Override
	public List<st> exec(st state) {
		NoAtom func=funcs.get(0);
		NoAtom func2=funcs.get(0);	
		if(func2==null){
			return executeUnaryNot(func,state);			
		}
		else
			return executeTestNot(func,func2,state);	
		
		
	}
//	(defun execute-test-not (Ex St)
//			  "Execute the (not <prop> <test>) form."
//			  (let ((B))
//			    (if (loop for wme in (st-wm St) never 
//				      (and (setq B (unify (second ex) wme (st-bindings st)))
//					   (eval (subst-bindings-quoted B (third ex)))))
//				(list St))))
	public List<st> executeTestNot(NoAtom prop,NoAtom test,st state){
		for(Term term:state.getWm()){
			Bindings temp=Unification.unify(prop, term, state.getBindings());
			if(temp!=null){
				if(((Func)test.substBindings(temp)).doFunc()!=null)
					return null;
			}		
		}
		List<st> states=new ArrayList<st>();
		states.add(state);
		return states;
	}


//	(defun execute-unary-not (Ex St)
//			  "Execute the (not <prop>) form."
//			  (if (loop for wme in (st-wm St) never 
//				    (unify (second ex) wme (st-bindings st)))
//			      (list St)))
	public List<st> executeUnaryNot(NoAtom func,st state){
		for(Term term:state.getWm()){
			if(Unification.unify(func, term, state.getBindings())!=null)
				return null;//
			
		}
		List<st> states=new ArrayList<st>();
		states.add(state);
		return states;
		
	}

		
	
	public void addFunc(NoAtom func2) {
		funcs.add(func2);
		
	}
	@Override
	public Term substBindings(Bindings bindings) {
		Not result=new Not();
		for(NoAtom fun:funcs){
			result.addFunc((NoAtom) fun.substBindings(bindings));
		}
		return result;
	}
}
